#include "pvm/pvmapi.h"
#include "lib/pvmsystem.h"

#include "lib/memory/pvmmemory.h"


static RFs* fs = NULL;

PVMCriticalSection* PVMGetCriticalForMmgr()
{
	return NULL;
}

void PVMFreeCriticalForMmgr()
{
}

pvm_bool PVMInitCritical(PVMCriticalSection *critical)
{
  return critical->CreateLocal()==KErrNone;
}

void PVMDeinitCritical(PVMCriticalSection *critical)
{
	critical->Close();
}

pvm_bool PVMEnterCritical(PVMCriticalSection *critical)
{
  critical->Wait();
  return critical->IsHeld();
}

void PVMLeaveCritical(PVMCriticalSection *critical)
{
	critical->Signal();
}

pvm_bool PVMInitEvent(PVMEventHandle *event)
{
	if (!event)
		return false;
	return event->CreateLocal() == KErrNone;
}

void PVMDeinitEvent(PVMEventHandle *event)
{
	if (!event)
		return;

	event->Close();
}

pvm_bool PVMWaitForEvent(PVMEventHandle *event)
{
	if (event)
	{
		event->Wait();
		return true;
	}

	return false;
}

void PVMSignalEvent(PVMEventHandle *event)
{
	if (!event)
		return;
	event->Signal();
}


void PVMInitThreadVar(PVMThreadHandle* outHandle)
{
	if(outHandle==NULL)
		return;
	
	outHandle->isValid = 0;
}

pvm_bool PVMIsThreadValid(PVMThreadHandle threadHandle)
{
	return threadHandle.isValid;
}

PVMThreadHandle PVMGetCurrentThread()
{
	PVMThreadHandle	threadHandle;
	
	threadHandle.isValid = true;

	return threadHandle;
}

pvm_bool PVMCreateThread(PVMThreadHandle* outHandle, PVMThreadStartRoutine routine, void *param)
{
	static int pvmThreadNum = 0;
	if(outHandle==NULL)
		return false;

	TBuf<128> threadName(_L("pvmthread"));
	
	threadName.AppendNum(pvmThreadNum);
	
	TInt  retVal = outHandle->thread.Create(threadName, routine, 64 * 1024, NULL, param);

	if(retVal==KErrNone)
	{
		++pvmThreadNum;
		outHandle->isValid = true;
		outHandle->thread.Resume();
		return true;
	}

	return false;
}

void PVMSuspendThread(PVMThreadHandle threadHandle)
{

	if(threadHandle.isValid==false)
		return;
	
	threadHandle.thread.Suspend();
}

void PVMResumeThread(PVMThreadHandle threadHandle)
{
	if(threadHandle.isValid==false)
		return;

	threadHandle.thread.Resume();
}

void PVMSleep(pvm_uint32 sleepTime)
{
	User::After(sleepTime*1000);
}

pvm_uint32 PVMGetMilliSecondsCount()
{
	const TTime unixEpochStart = TDateTime(1970, EJanuary, 0, 0, 0, 0, 0);
	TTime time;

	time.UniversalTime();
	return time.MicroSecondsFrom(unixEpochStart).Int64() / 1000;
}

PVMFileHandle PVMFileOpen(const pvm_char* fileName, pvm_int32 mode)
{
	TUint fileMode = EFileShareAny;
	RFile* file = NULL;
	
	if(fileName==NULL)
		return NULL;
	
	if(fs==NULL)
		return NULL;

	file = new RFile;
	
	if(mode&PVM_READ)
		fileMode = fileMode | EFileRead;
	
	if(mode&PVM_WRITE)
		fileMode = fileMode | EFileWrite;
	
	TPtrC aName((TUint16*)fileName);
	TInt err = KErrNone;
	
	if(mode&PVM_OPEN_EXISTING)
	{
		err = file->Open(*fs, aName, fileMode);		
	}
	
	if(mode&PVM_OPEN_EXISTING)
	{
		err = file->Open(*fs, aName, fileMode);		
	}
	
	if(mode&PVM_CREATE_ALWAYS)
	{
		err = file->Replace(*fs, aName, fileMode);		
	}
	
	if(mode&PVM_OPEN_ALWAYS)
	{
		err = file->Open(*fs, aName, fileMode);
		if(err!=KErrNone)
			err = file->Create(*fs, aName, fileMode);
	}
	
	
	if(err!=KErrNone)
	{
		delete file;
		return NULL;
	}
	
	return file;
}

void PVMFileClose(PVMFileHandle file)
{
	if(file==NULL)
		return;
	file->Close();
	delete file;
}

pvm_bool PVMFileRead(PVMFileHandle file, void* buffer, pvm_size nBytes, pvm_size* readResult)
{
	if(readResult==NULL)
		return false;
	
	*readResult = 0;

	if(file==NULL)
		return false;

	TPtr8 ptr((TUint8*)buffer, (TInt)nBytes);
	
	TInt err = file->Read(ptr);
	if(err!=KErrNone)
	{
		return false;
	}
	
	*readResult = ptr.Size();
	
	return true;
}

pvm_bool PVMFileWrite(PVMFileHandle file, void* buffer, pvm_size nBytes, pvm_size* writeResult)
{
	if(writeResult==NULL)
		return false;

	*writeResult = 0;
	
	if(file==NULL)
		return false;
	
	TPtrC8  ptr((TUint8*)buffer, (TInt)nBytes);
	
	TInt err = file->Write(ptr);
	if(err!=KErrNone)
	{
		return false;
	}
	
	*writeResult = ptr.Size();
	
	return true;
}

pvm_file_size PVMFileSize(PVMFileHandle file)
{
	if(file==NULL)
		return PVM_INVALID_FILE_SIZE;
	TInt aSize = 0;
	TInt err = file->Size(aSize);
	if(err!=KErrNone)
		return PVM_INVALID_FILE_SIZE;
	return aSize;	
}

pvm_bool PVMFileSeek(PVMFileHandle file, pvm_file_size pos, pvm_int32 origin)
{
	if(file==NULL)
		return false;

	TSeek mode;
	TInt aPos = pos;
	switch(origin)
	{
	case EPVM_SEEK_BEGIN:
		mode = ESeekStart;
		break;
	case EPVM_SEEK_CURRENT:
		mode = ESeekCurrent;
		break;
	case EPVM_SEEK_END:
		mode = ESeekEnd;
		break;
	default:
		return false;
	};
	TInt err = file->Seek(mode, aPos);
	if(err!=KErrNone)
		return false;
	return true;
}

pvm_file_size PVMFileTell(PVMFileHandle file)
{
	if(file==NULL)
		return PVM_INVALID_FILE_SIZE;

	TSeek aMode = ESeekCurrent;
	TInt aPos = 0;

	TInt err = file->Seek(aMode, aPos);
	if(err!=KErrNone)
		return PVM_INVALID_FILE_SIZE;
	return aPos;  
}


pvm_bool PVMSystemInit()
{
	if(fs!=NULL)
		return false;
	
	fs = new RFs;
	if(fs->Connect()!=KErrNone)
	{
		delete fs;
		fs = NULL;
		return false;
	}
	if (fs->ShareAuto() != KErrNone)
	{
		fs->Close();
		delete fs;
		fs = NULL;
		return false;		
	}
	
	return true;
}

void PVMSystemDeinit()
{
	if(fs==NULL)
		return;
	fs->Close();
	delete fs;
}
